package com.android.kotlincoroutinemvvmdemo.viewmodel
import android.util.Log
import com.android.kotlincoroutinemvvmdemo.Constants
import com.android.kotlincoroutinemvvmdemo.callback.ICallback
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.callbackFlow
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.flow.receiveAsFlow
import kotlinx.coroutines.flow.shareIn
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch
import kotlinx.coroutines.suspendCancellableCoroutine
import java.lang.Exception
import kotlin.coroutines.resume
import kotlin.coroutines.resumeWithException

class FlowUseViewModel : BaseViewModel() {

    //通过shareIn把flow转化为SharedFlow
    val flowConvertSharedFlow by lazy {
        flow {
            emit("1、flow")
            emit("2、convert")
            emit("3、SharedFlow")
        }.shareIn(
            //协程作用域范围
            this,
            //立即开始
            SharingStarted.Eagerly,
            //重复执行次数
            replay = 3
        ).onStart {
            Log.d(Constants.TAG, "--SharedFlow--onStart--")
        }
    }

    //通过stateIn把flow转化为StateFlow
    val flowConvertStateFlow by lazy {
        flow {
            emit("1、state")
            emit("2、init")
            emit("3、collector")
        }.stateIn(
            this,
            SharingStarted.Eagerly,
            "StateFlow initial value"
        ).onStart {
            Log.d(Constants.TAG, "--StateFlow--onStart--")
        }
    }

    private val _loadingChannel = Channel<Boolean>()

    val loadingShow = _loadingChannel.receiveAsFlow()

    private suspend fun loadStart() {
        _loadingChannel.send(true)
    }

    private suspend fun loadFinish() {
        _loadingChannel.send(false)
    }

    suspend fun suspendCancellableData() : String {
        return try {
             getSccInfo()
        } catch (e: Exception) {
            "error:${e.message}"
        }
    }

    private suspend fun getSccInfo(): String = suspendCancellableCoroutine { continuation ->
        val callback = object : ICallback<String> {
            override fun onSuccess(result: String?) {
                //1.返回结果  将结果赋值给挂起函数的返回值
                //2.如果调用了continuation.cancel()  resume()的结果就不返回了  因为协程取消了
                continuation.resume(result ?: "empty")
            }

            override fun onError(exception: Exception) {
                //将异常抛给上层  交给上层处理
                continuation.resumeWithException(exception)
            }
        }

        continuation.invokeOnCancellation {
            //协程取消时调用  可以在这里进行解注册
            Log.d(Constants.TAG, "invokeOnCancellation")
        }

        //模拟网络请求
        Thread {
            Thread.sleep(500)
            //成功获取数据
            //callback.onSuccess("get data  successful")
            callback.onError(RuntimeException("网络错误  获取数据失败"))
        }.start()

        //模拟协程取消
        //continuation.cancel(RuntimeException("协程取消了"))
    }

    fun getSearchCallbackFlow(): Flow<Boolean> = callbackFlow {
        val callback = object : ICallback<String> {
            override fun onSuccess(result: String?) {
                trySend(true)
            }

            override fun onError(exception: Exception) {
                trySend(false)
            }
        }

        //模拟网络请求
        Thread {
            Thread.sleep(500)
            //callback.onSuccess("找到目的地")
            callback.onError(RuntimeException("网络出现错误"))
        }.start()

        //这是一个挂起函数 flow被关闭的时候 会执行里面的代码 可以在这里执行解注册的操作
        awaitClose {
            Log.d(Constants.TAG, "search---awaitClose---search")
        }
    }

    fun getDesCallbackFlow(isSuccess: Boolean): Flow<String?> = callbackFlow {
        val callback = object : ICallback<String> {
            override fun onSuccess(result: String?) {
                trySend(result)
            }

            override fun onError(exception: Exception) {
                trySend(exception.message)
            }
        }

        //模拟网络请求
        Thread {
            Thread.sleep(500)
            if (isSuccess) {
               //到达目的地
                callback.onSuccess("到达目的地")
            } else {
                callback.onError(RuntimeException("没有到达目的地"))
            }
        }.start()

        awaitClose {
            Log.d(Constants.TAG, "go---awaitClose---go")
        }
    }

}